/* Includes ------------------------------------------------------------------*/
#include "log.h"
#include "cx32l003_hal_uart.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static void SerialInit(uint32_t baud_rate);
static void SerialSend(uint8_t data);

/* Private functions ---------------------------------------------------------*/
/**
 * @brief  Configures the UART peripheral.
 * @param  huart: pointer to a UART_HandleTypeDef structure that contains
 *                the configuration information for the specified UART module.
 * @retval None
 */
static void Log_UART_SetConfig(UART_HandleTypeDef* huart) {
    /*------- UART-associated registers setting : SCON Configuration ------*/
    /* Configure the UART Word Length and mode:
           Set the DBAUD bits according to huart->Init.BaudDouble value
       Set the SM bits according to huart->Init.WordLength value
       Set REN bits according to huart->Init.Mode value */
    MODIFY_REG(huart->Instance->SCON, (UART_SCON_DBAUD | UART_SCON_SM0_SM1 | UART_SCON_REN), huart->Init.BaudDouble | huart->Init.WordLength | huart->Init.Mode);

    /*-------------------------- UART BAUDCR Configuration ---------------------*/
    huart->Instance->BAUDCR = (((((huart->Init.BaudDouble >> UART_SCON_DBAUD_Pos) + 1) * HAL_RCC_GetPCLKFreq()) / (32 * (huart->Init.BaudRate)) - 1) & UART_BAUDCR_BRG) | UART_BAUDCR_SELF_BRG;

    __HAL_UART_ENABLE_IT(huart, UART_IT_TC | UART_IT_RXNE);
}

UART_HandleTypeDef huart1 = {0};

/**
 * @brief  This function initializes the log interface
 * @param  None
 * @retval None
 */
void LogInit(void) {
#ifdef LOG_METHOD_SERIAL
    SerialInit(LOG_SERIAL_BPS);
#endif
}

void logout(bool success) {
    if (true == success) {
        printf("$P\n");
    } else {
        printf("$F\n");
    }
}

/**
 * @brief UART1 Initialization Function
 * @param None
 * @retval None
 */
static void SerialInit(uint32_t baud_rate) {
    huart1.Instance = UART1;
    huart1.Init.BaudRate = baud_rate;
    huart1.Init.BaudDouble = UART_BAUDDOUBLE_ENABLE;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;

    if (huart1.gState == HAL_UART_STATE_RESET) {
        /* Allocate lock resource and initialize it */
        huart1.Lock = HAL_UNLOCKED;

        GPIO_InitTypeDef GPIO_InitStruct = {0};
        /* Peripheral clock enable */
        __HAL_RCC_UART1_CLK_ENABLE();

        __HAL_RCC_GPIOD_CLK_ENABLE();
        /**UART1 GPIO Configuration
        PD5     ------> UART1_TXD
        PD6     ------> UART1_RXD
        */
        GPIO_InitStruct.Pin = GPIO_PIN_5;
        GPIO_InitStruct.Mode = GPIO_MODE_AF;
        GPIO_InitStruct.OpenDrain = GPIO_PUSHPULL;
        GPIO_InitStruct.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
        GPIO_InitStruct.SlewRate = GPIO_SLEW_RATE_HIGH;
        GPIO_InitStruct.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Alternate = GPIO_AF5_UART1_TXD;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_6;
        GPIO_InitStruct.Mode = GPIO_MODE_AF;
        GPIO_InitStruct.Alternate = GPIO_AF5_UART1_RXD;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    }

    huart1.gState = HAL_UART_STATE_BUSY;

    /* Set the UART Communication parameters */
    Log_UART_SetConfig(&huart1);

    /* Initialize the UART state */
    huart1.ErrorCode = HAL_UART_ERROR_NONE;
    huart1.gState = HAL_UART_STATE_READY;
    huart1.RxState = HAL_UART_STATE_READY;
}

void SerialSend(uint8_t data) {
    HAL_UART_Transmit(&huart1, &data, 1, 1000);
}

#ifdef __GNUC__
int _write(int file, char* data, int len) {
    int bytes_written;

    for (bytes_written = 0; bytes_written < len; bytes_written++) {
#ifdef LOG_METHOD_SERIAL
        // expand LF to CR-LF
        if (*data == '\n') {
            SerialSend('\r');
        }
        SerialSend(*data);
#else  // Another method to log
#ifdef LOG_METHOD_RAM
        *LOG_RAM_CHAR = *data;
#endif
#endif
        data++;
    }

    return bytes_written;
}

#else
int fputc(int ch, FILE* f) {
/* Your implementation of fputc(). */
#ifdef LOG_METHOD_SERIAL
    SerialSend(ch);
#else  // Another method to log
#ifdef LOG_METHOD_RAM
    *LOG_RAM_CHAR = *data;
#endif
#endif

    return 0;
}
#endif  //__GNUC__

// int fputc(int ch, FILE *f) {
//
//	/* Your implementation of fputc(). */
//	uint8_t ch_data;
//	ch_data = ch;
//	HAL_LPUART_Transmit_printf(&sLPUartxHandle,&ch_data);
//	while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
//	return ch;
// }

// int fputc(int ch)
//{

// USART_SendData(USART1, (u8) ch);

// while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);

// return ch;

//}
void panic(const char* func) {
    // If panic info enabled, print it out
    printf("Panic call from %s\n", func);
    /* Add any panic string desired or while loop as needed */
}
